/*
Audica Uploader - application for convenient uploading to various file hostings
Copyright (C) 2011-2012 Makarov Andrey (Winand)

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "networkuploadmanager.h"
#include "dbgform.h"
#include <QApplication>
#include <QDesktopWidget>

NetworkUploadManager::NetworkUploadManager(QObject *parent) :
    QObject(parent)
{
    QStringList PotentialScriptLibs =
            QDir(appPath()).entryList(QStringList(SCRIPT_PLUGINS), QDir::Files);
    foreach(QString lib, PotentialScriptLibs)
        loadScriptLib(appPath() + "/" + lib);
    connect(&netw, SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)), SLOT(authenticationRequired(QNetworkReply*, QAuthenticator*)));
}

void NetworkUploadManager::newUploadTaskInput(const QList<QString> message) {
    /*UploadResult* ur = new UploadResult(this);
    ur->appendUrl("111", "222");
    ur->appendUrl("333", "444");
    ur->appendUrl("555", "666");
    frmsummary.addUploadResult("gsdfgsf", new UploadResult(this));
    frmsummary.addUploadResult("filepath", ur);
    frmsummary.show();*/

    qDebug() << "message" << QTime::currentTime() << ":" << message;
    UploadWorker* uploader = new UploadWorker("scriptrghost.js", this);
    connect(uploader, SIGNAL(finished(QString, UploadResult*)), this, SLOT(finished(QString, UploadResult*)));
    connect(uploader, SIGNAL(timeout()), this, SLOT(timeout()));
    workers.append(uploader);
    uploader->setPluginsList(&scriptPlugins);
    //form
    UploadForm* form = newUploadForm(); //create new upload window
    connect(uploader, SIGNAL(progress(qint64, qint64)), form, SLOT(setProgress(qint64, qint64)));
    connect(uploader, SIGNAL(setStatusText(QString)), form, SLOT(setStatusText(QString)));
    form->show();
    //
    uploader->upload(message.last());
}

void NetworkUploadManager::animateWindows(int fromIdx) {
    for(int i = fromIdx; i < forms.count(); i++) {
        QPropertyAnimation* animation = new QPropertyAnimation(forms.at(i), "geometry");
        animation->setDuration(ANIM_TIME);
        animation->setStartValue(forms.at(i)->geometry());
        animation->setEndValue(QRect(formpos.at(i), forms.at(i)->size()));
        if(formpos.at(i).x() == forms.at(i)->x() && formpos.at(i).y() > forms.at(i)->y())
            animation->setEasingCurve(QEasingCurve::OutBounce); //bounce when falling down
        else animation->setEasingCurve(QEasingCurve::InQuad); //accelerating when flying up
        animation->start(QAbstractAnimation::DeleteWhenStopped);
    }
}

UploadForm* NetworkUploadManager::newUploadForm() {
    UploadForm* frm = new UploadForm();
    connect(frm, SIGNAL(userCanceled()), this, SLOT(userCanceled()));

    QSize d(QApplication::desktop()->width(), QApplication::desktop()->height()); //screen size
    QSize f(OFF_FRM(frm->width()), OFF_FRM(frm->height())); //form size with offsets
    int itemsInCol = d.height() / f.height(); //max number of forms in column
    QPoint pos(forms.count() / itemsInCol + 1, forms.count() % itemsInCol + 1); //position of form in form-grid
    QPoint phys_pos(d.width() - f.width() * pos.x(), d.height() - f.height() * pos.y()); //position of form on screen
    frm->move(phys_pos);

    forms.append(frm); //add to controlled forms
    formpos.append(phys_pos);
    return frm;

}

//load /lib/ as script plugin
bool NetworkUploadManager::loadScriptLib(const QString lib) {
    QLibrary libplug(lib);
    if(libplug.load()) {
        scriptplugin plug;
        plug.instProc = (loadScriptPlugin)libplug.resolve("inst");
        if(plug.instProc) {
            loadScriptPlugin infoProc = (loadScriptPlugin)libplug.resolve("info");
            if(infoProc) {
                QObject* info = infoProc();
                QString name;
                if(QMetaObject::invokeMethod(info, "name",
                                             Q_RETURN_ARG(QString, name))) {
                    if(name.length()) {
                        if(!QMetaObject::invokeMethod(info, "version",
                                                      Q_RETURN_ARG(int, plug.version))) {
                            plug.version = 0x000000;
                            qDebug() << "load script plugin: unknown plugin version";
                        }
                        QMetaObject::invokeMethod(info, "description",
                                                  Q_RETURN_ARG(QString, plug.description));
                        name = name.left(32).toLatin1(); //chop to 32 latin1 symbols
                        if(!scriptPlugins.contains(name)) {
                            scriptPlugins.insert(name, plug);
                            qDebug() << "Script plugin" << name << "loaded";
                            return true;
                        } else qDebug() << "load script plugin: plugin returned empty name";
                    } else qDebug() << "load script plugin: plugin returned empty name";
                } else qDebug() << "load script plugin: name slot call failed";
                delete info; //kill info object
            } else qDebug() << "load script plugin: lib isn't a script plugin" << lib;
        } else qDebug() << "load script plugin: lib isn't a script plugin" << lib;
    } else qDebug() << "load script plugin: lib not found" << lib;
    return false;
}

bool NetworkUploadManager::killUploadTask(int index) {
    if(index != -1) {
        forms.takeAt(index)->deleteLater(); //delete form
        formpos.removeLast();
        workers.takeAt(index)->deleteLater(); //delete worker
        animateWindows(index); //fly to new positions
        return true;
    } else qCritical() << "unknown upload task index" << index;
    return false;
}

//Cancel button pressed
void NetworkUploadManager::userCanceled() {
    UploadForm* sender = qobject_cast<UploadForm*>(QObject::sender());
    killUploadTask(forms.indexOf(sender));
}

//script successfully finished
void NetworkUploadManager::finished(const QString filepath, UploadResult* res) {
    if(!res->hasFailed()) {
        frmsummary.addUploadResult(filepath, res);
        frmsummary.show();
        UploadWorker* sender = qobject_cast<UploadWorker*>(QObject::sender());
        killUploadTask(workers.indexOf(sender));
    } else qDebug() << "Upload error" << res->fail_desc;
}

//waited for too long, abortion
void NetworkUploadManager::timeout() {
    UploadWorker* sender = qobject_cast<UploadWorker*>(QObject::sender());
    int idx = workers.indexOf(sender);
    if(idx != -1) {
        UploadForm* frm = forms.at(idx);
        frm->setButtonConfirmation(false);
        frm->setButtonText(tr("OK"));
        frm->setStatusText(tr("Timeout exceeded"));
    } else qDebug() << "unknown worker" << sender;
}

void NetworkUploadManager::authenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator) {
    qDebug() << "authenticationRequired";
    authenticator->setUser(QString("admin"));
    authenticator->setPassword(QString("admin1908"));
}
